from datetime import datetime
import logging
from flask_babel import _
from controllers.errors.online_mall.shop_errors import HShopNotFoundError, HTagRefNotFoundError, HTagRefParamError
from controllers.errors.online_mall.tag_errors import HProdTagNotFoundError
from core.entities.account_role import AccountWrap
from extensions.ext_database import db
from models.online_mall.prod_other import MProductTag,MProductTagProduct
from werkzeug.exceptions import InternalServerError

from models.online_mall.shop_msg import MShop
class ProdTagService:
    @staticmethod
    def get_tag_list(tenant_id:str,args:dict) -> dict:
        try:
            query = db.session.query(MProductTag).filter(MProductTag.tenant_id == tenant_id, MProductTag.deleted_at == None)
            total = 0
            has_more = False
            if 'id' in args and args.get('id'):
                query = query.filter(MProductTag.id == args.get('id'))
                total = query.count()
            else:
                if 'title' in args and args.get('title'):
                    query = query.filter(MProductTag.title.ilike(f"%{args.get('title')}%"))
                if 'shop_id' in args:
                    query = query.filter(MProductTag.shop_id == args.get('shop_id'))
                if 'status' in args and args.get('status') is not None:
                    query = query.filter(MProductTag.status == args.get('status'))
                if 'list_style' in args and args.get('list_style'):
                    query = query.filter(MProductTag.list_style == args.get('list_style'))
                if 'is_system' in args and args.get('is_system') is not None:
                    query = query.filter(MProductTag.is_system == args['is_system'])
                total = query.count()
                page = args.get("page")
                page_size = args.get("page_size")
                if page and page_size and page >0 and page_size >0:
                    query = query.order_by(MProductTag.seq.asc())
                    query = query.offset((page-1)*page_size).limit(page_size)
                    has_more = total > page*page_size
            data = query.all()
            return {
                "total":total,
                "has_more":has_more,
                "data":data
            }
        except Exception as e:
            db.session.rollback()
            logging.error(e)
            return {
                "total":0,
                "has_more":False,
                "data":[],
                "error":str(e)
            }
        
    @staticmethod
    def _next_tag_seq(tenant_id:str|None)->int:
        if tenant_id:
            max_seq_row = db.session.query(MProductTag.seq).filter(MProductTag.tenant_id==tenant_id).order_by(MProductTag.seq.desc()).first()
            max_seq = max_seq_row[0] if max_seq_row else None
            return 1 if not max_seq else max_seq + 1
        return 1
    @staticmethod
    def create_tag(account:AccountWrap,args:dict)->MProductTag:
        tag = MProductTag(
            tenant_id = account.current_tenant_id, # type: ignore
            created_by = account.id, # type: ignore
        )
        new_seq = ProdTagService._next_tag_seq(account.current_tenant_id)
        if 'seq' not in args or not args['seq']:
            args['seq'] = new_seq
        ProdTagService._fill_tag_params(args, tag)
        try:
            db.session.add(tag)
            db.session.commit()
            return tag
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
        
    @staticmethod
    def delete_tag(account:AccountWrap,tag_id):
        tag = db.session.get(MProductTag,tag_id)
        if not tag:
            raise HProdTagNotFoundError(tag_id)
        try:
            tag.status = False
            tag.deleted_at = datetime.now()
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
    @staticmethod
    def update_tag(account:AccountWrap,args:dict)->MProductTag:
        tag_id = args.get('id')
        if not tag_id:
            raise HProdTagNotFoundError(tag_id)
        tag = db.session.get(MProductTag, tag_id)
        if not tag:
            raise HProdTagNotFoundError(tag_id)
        ProdTagService._fill_tag_params(args, tag)
        try:
            tag.updated_at = datetime.now()
            db.session.commit()
            return tag
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))

    @staticmethod
    def _fill_tag_params(args:dict, tag:MProductTag):
        if 'title' in args and args['title']:
            tag.title = args['title']
        if 'shop_id' in args and args['shop_id']:
            shop = db.session.get(MShop,args['shop_id'])
            if not shop:
                raise HShopNotFoundError(args['shop_id'])
            tag.shop_id = shop.id
        if 'status' in args and args['status'] is not None:
            tag.status = args['status']
            # if not tag.status:
            #     tag.deleted_at = datetime.now()
        if 'is_system' in args and args['is_system'] is not None:
            tag.is_system = args['is_system']
        if 'list_style' in args and args['list_style']:
            tag.list_style = args['list_style']
        if 'prod_count' in args and args['prod_count']:
            tag.prod_count = args['prod_count']
        if 'seq' in args and args['seq']:
            tag.seq = args['seq']
        

    @staticmethod
    def get_tag_ref_list(tenant_id,args:dict)->dict:
        try:
            query = db.session.query(MProductTagProduct).filter(MProductTagProduct.tenant_id == tenant_id)
            total = 0
            has_more = False
            if 'id' in args and args.get('id'):
                query = query.filter(MProductTagProduct.id == args.get('id'))
                total = query.count()
            else:
                if 'title' in args and args.get('title'):
                    query = query.filter(MProductTag.title.ilike(f"%{args.get('title')}%"))
                if 'tag_id' in args:
                    query = query.filter(MProductTagProduct.tag_id == args.get('tag_id'))
                if 'shop_id' in args:
                    query = query.filter(MProductTagProduct.shop_id == args.get('shop_id'))
                if 'status' in args and args.get('status') is not None:
                    query = query.filter(MProductTagProduct.status == args.get('status'))
                
                total = query.count()
                page = args.get("page")
                page_size = args.get("page_size")
                if page and page_size and page >0 and page_size >0:
                    query = query.order_by(MProductTag.seq.asc())
                    query = query.offset((page-1)*page_size).limit(page_size)
                    has_more = total > page*page_size
            data = query.all()
            return {
                "total":total,
                "has_more":has_more,
                "data":data
            }
        except Exception as e:
            db.session.rollback()
            logging.error(e)
            return {
                "total":0,
                "has_more":False,
                "data":[],
                "error":str(e)
            }
        
    @staticmethod
    def _fill_tag_ref_params(args:dict,tag_ref:MProductTagProduct):
        if 'shop_id' in args and args['shop_id']:
            tag_ref.shop_id = args['shop_id']
            shop = db.session.get(MShop,args['shop_id'])
            if not shop:
                raise HShopNotFoundError(args['shop_id'])
            
        if 'tag_id' in args and args['tag_id']:
            tag_ref.tag_id = args['tag_id']
            if not tag_ref.tag_id:
                raise HTagRefParamError("Tag id is required")
        if 'prod_id' in args and args['prod_id']:
            tag_ref.prod_id = args['prod_id']
            if not tag_ref.prod_id:
                raise HTagRefParamError("Product id is required")
        if 'status' in args and args['status'] is not None:
            tag_ref.status = args['status']
    @staticmethod
    def create_tag_ref(account:AccountWrap,args:dict)->MProductTagProduct:
        tag_ref = MProductTagProduct(
            tenant_id = account.current_tenant_id, # type: ignore
            created_by = account.id, # type: ignore
        )
        
        ProdTagService._fill_tag_ref_params(args, tag_ref)
        try:
            db.session.add(tag_ref)
            db.session.commit()
            return tag_ref
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
        
    @staticmethod
    def update_tag_ref(account:AccountWrap,args:dict)->MProductTagProduct:
        if 'id' not in args or not args['id']:
            raise HTagRefParamError(_("Tag ID is required"))
        tag_ref = db.session.get(MProductTagProduct, args["id"])
        if not tag_ref:
            raise HTagRefNotFoundError(args["id"])
        ProdTagService._fill_tag_ref_params(args, tag_ref)

        try:
            db.session.commit()
            return tag_ref
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))
        
    @staticmethod
    def del_tag_ref(account:AccountWrap,ref_id:int):
        
        tag_ref = db.session.get(MProductTagProduct, ref_id)
        if not tag_ref:
            raise HTagRefNotFoundError(str(ref_id))
        
        try:
            db.session.commit()
            return tag_ref
        except Exception as e:
            db.session.rollback()
            raise InternalServerError(str(e))